<?
class ZPlus_Plugin
{
  private static $root;
  private static $pathInfo;

  public static function translatePlugin($plugin)
  {
    return ucfirst(self::translateMethod($plugin));
  }

  public static function translateMethod($method)
  {
    while (($p = strpos($method, '-')) !== false)
    {
      $method = substr($method, 0, $p).ucfirst(substr($method, $p + 1));
    }
    return $method;
  }

  public static function run($root, $plugin, $method, array $opts = array())
  {
    // new bootstrap
    $bs = $root.'_Bootstrap';
    $bootstrap = new $bs();
    self::$root = $root;
    // parse parameters
    $all_mode = isset($opts['mode']) ? $opts['mode'] : array();
    $default = isset($opts['default_mode']) ? $opts['default_mode'] : 'page';
    $params = self::parsePathInfo($plugin, $method, $all_mode, $default);
    $plugin = $params['plugin'];
    $method = $params['method'];
    $mode = $params['mode'];

    if ($mode == 'page')
      self::runPage($bootstrap, $plugin, $method);
    else
      self::runMode($bootstrap, $mode, $plugin, $method);
  }

  public static function runPage($bootstrap, $plugin, $method)
  {
    try
    {
      // init
      $bootstrap->init($plugin, $method);
      // new object
      $plugin_folder = self::translatePlugin($plugin);
      $clname = self::$root.'_'.$plugin_folder.'_Controller';
      $obj = new $clname();
      $view = new Zend_View();
      $view->setScriptPath(MODULE_DIR.'/'.self::$root.'/'.$plugin_folder.'/View/');
      $obj->view = $view;
      // do action
      $action_method = self::translateMethod($method).'Action';
      if (!method_exists($obj, $action_method))
        throw new Exception('Undefined method '.$method.' in '.get_class($obj));
      $content = $obj->$action_method();
      // render
      if ($content === null || $content === false)
        $content = $obj->view->render($method.'.phtml');
      $bootstrap->render($content);
    }
    catch (Exception $e)
    {
      try
      {
        $bootstrap->error($e);
      }
      catch (Exception $e2)
      {
        echo "<pre>\n";
        echo $e->getMessage()."\n";
        echo $e->getTraceAsString()."\n";
      }
    }
  }

  public static function runMode($bootstrap, $mode, $plugin, $method)
  {
    $mode = ucfirst($mode);
    // init
    $bootstrap->{'init'.$mode}($plugin, $method);
    // new object
    $plugin_folder = self::translatePlugin($plugin);
    $clname = self::$root.'_'.$plugin_folder.'_'.$mode;
    $obj = new $clname();
    $obj->{self::translateMethod($method).'Action'}();
  }

  public static function paramEncode(array $params)
  {
    $q = array();
    foreach ($params as $k => $v)
      $q[] = urlencode($k).'='.urlencode($v);
    return implode('&', $q);
  }
  
  public static function paramConcat($url, array $params)
  {
    if (strpos($url, '?') === false)
      $url .= '?';
    $url .= self::paramEncode($params);
    return $url;
  }

  public static function getUrl($plugin, $method, $params = array())
  {
    $url = $_SERVER['SCRIPT_NAME'].'/'.$plugin.'/'.$method;
    if (!empty($params))
      $url = self::paramConcat($url, $params);
    return $url;
  }

  public static function getUrlMode($mode, $plugin, $method, $params = array())
  {
    $url = $_SERVER['SCRIPT_NAME'].'/'.$plugin.'/'.$mode.'/'.$method;
    if (!empty($params))
      $url = self::paramConcat($url, $params);
    return $url;
  }

  public static function getResourceUrl($rel_url, $params = array())
  {
    $url  = $_SERVER['SCRIPT_NAME'];
    $p = strrpos($url, '/');
    if ($p !== false) $url = substr($url, 0, $p);
    $url .= '/'.$rel_url;
    if (!empty($params))
      $url = self::paramConcat($url, $params);
    return $url;
  }

  public static function redirectUrl($url, $params = array(), $exit = false)
  {
    if (!empty($params))
    {
      $q = array();
      foreach ($params as $k => $v)
        $q[] = urlencode($k).'='.urlencode($v);
      $url .= '?'.implode('&', $q);
    }
    header('Location: '.$url);
    if ($exit) die;
  }

  public static function redirect($plugin, $method, $params = array(), $exit = false)
  {
    $url = $_SERVER['SCRIPT_NAME'].'/'.$plugin.'/'.$method;
    self::redirectUrl($url, $params, $exit);
  }

  public static function getParam($key, $def = null)
  {
    if (!isset($_REQUEST[$key])) return $def;
    return $_REQUEST[$key];
  }

  public static function getParams(array $keys, $need_all_keys = true)
  {
    $ps = array();
    foreach ($keys as $k)
    {
      if (isset($_REQUEST[$k]))
      {
        if ($need_all_keys || !empty($_REQUEST[$k]))
          $ps[$k] = $_REQUEST[$k];
      }
      else if ($need_all_keys)
      {
        $ps[$k] = null;
      }
    }
    return $ps;
  }

  public static function getPathInfo($key, $def = null)
  {
    if (empty(self::$pathInfo)) return $def;
    if (!isset(self::$pathInfo[$key])) return $def;
    return self::$pathInfo[$key];
  }

  private static function parsePathInfo($plugin, $method, array $all_mode = array(), $default_mode = 'page')
  {
    $r = array('plugin' => $plugin, 'method' => $method, 'mode' => $default_mode);
    if (!empty($_SERVER['PATH_INFO']))
    {
      $ps = explode('/', $_SERVER['PATH_INFO']);
      $pc = count($ps);
      if ($pc > 1 && !empty($ps[1]))
        $r['plugin'] = $ps[1];
      if ($pc > 2 && !empty($ps[2]))
      {
        if (in_array($ps[2], $all_mode) && $pc > 3 && !empty($ps[3]))
        {
          $r['mode'] = $ps[2];
          $r['method'] = $ps[3];
        }
        else
        {
          $r['method'] = $ps[2];
        }
      }
    }
    self::$pathInfo = $r;
    return $r;
  }
}
